package fr.umlv.jee.jawp.persistence.dao;

import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.List;

import org.springframework.transaction.annotation.Transactional;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;

import fr.umlv.jee.jawp.persistence.object.Category;

public class CategoryDAO implements ICategoryDAO {
	static CategoryDAO dao = null;
	DBCollection categoryCollection;
	ProductDAO productDAO;
	int currentId;

	public CategoryDAO() throws UnknownHostException, MongoException {
		// connect to mongoDB (ip and port number are optional)
		Mongo mongo = new Mongo();

		// get database from MongoDB,
		// if database doesn't exists, mongoDB will create it automatically
		DB db = mongo.getDB("JAWP_DB");

		// Get collection from MongoDB, database named "Categories"
		// if collection doesn't exists, mongoDB will create it automatically
		categoryCollection = db.getCollection("Categories");
		// categoryCollection.drop();

		// query the last id
		DBCursor cursor = categoryCollection.find()
				.sort(new BasicDBObject("id", -1)).limit(1);
		// get the result
		if (cursor.size() == 0)
			currentId = 0;
		else {
			DBObject result = cursor.next();
			currentId = ((Integer) result.get("id")).intValue() + 1;
		}
	}

	/*************************************
	 * Creation
	 *************************************/

	@Override
	public Category createNewCategory(String name, int motherCategoryId) {
		Category category = getCategoryByNameAndMotherCategory(name,
				motherCategoryId);
		if (category == null) {
			category = new Category();
			category.setId(currentId);
			category.setName(name);
			category.setMotherCategory(motherCategoryId);

			// create a document to store key and value
			BasicDBObject document = new BasicDBObject();
			document.put("id", currentId);
			document.put("name", name);
			document.put("motherCategoryId", motherCategoryId);

			// save it into collection
			categoryCollection.insert(document);

			// increment current id
			currentId++;
		}
		return category;
	}

	@Override
	public Category createNewCategory(String name) {
		return createNewCategory(name, -1);
	}

	/*************************************
	 * Getter
	 *************************************/

	@Override
	public List<Category> getCategories() {
		// search query
		BasicDBObject searchQuery = new BasicDBObject();

		// query it
		DBCursor cursor = categoryCollection.find(searchQuery);

		List<Category> categorys = new LinkedList<Category>();
		while (cursor.hasNext()) {
			DBObject object = cursor.next();
			Integer motherCategory = (Integer) object.get("motherCategoryId");

			Category category = new Category();
			category.setId((Integer) object.get("id"));
			category.setName((String) object.get("name"));
			category.setMotherCategory(motherCategory == null ? -1 : motherCategory);

			categorys.add(category);
		}

		return categorys;
	}

	@Override
	public List<Category> getCategoriesByMotherId(int motherCategoryId) {
		// search query
		BasicDBObject searchQuery = new BasicDBObject();

		// query it
		DBCursor cursor = categoryCollection.find(searchQuery);
		searchQuery.put("motherCategoryId", motherCategoryId);

		List<Category> categorys = new LinkedList<Category>();
		while (cursor.hasNext()) {
			DBObject object = cursor.next();

			Category category = new Category();
			category.setId((Integer) object.get("id"));
			category.setName((String) object.get("name"));
			category.setMotherCategory(motherCategoryId);

			categorys.add(category);
		}

		return categorys;
	}

	@Override
	public List<Category> getCategoriesByMotherId() {
		return getCategoriesByMotherId(-1);
	}

	@Override
	public Category getCategoriesById(int id) {
		// search query
		BasicDBObject searchQuery = new BasicDBObject();
		searchQuery.put("id", id);

		// query it
		DBCursor cursor = categoryCollection.find(searchQuery);

		if (cursor.size() == 0) {
			return null;
		}

		DBObject object = cursor.next();

		Category category = new Category();
		category.setId(id);
		category.setName((String) object.get("name"));
		category.setMotherCategory((Integer) object.get("motherCategoryId"));

		return category;
	}

	@Override
	public Category getCategoryByNameAndMotherCategory(String name, int categoryId) {
		// search query
		BasicDBObject searchQuery = new BasicDBObject();
		searchQuery.put("name", name);
		searchQuery.put("motherCategoryId", categoryId);

		// query it
		DBObject object = categoryCollection.findOne(searchQuery);

		if (object == null) {
			return null;
		}

		Category category = new Category();
		category.setId((Integer) object.get("id"));
		category.setName(name);
		category.setMotherCategory(categoryId);

		return category;

	}

	@Override
	public Category getCategoryByNameAndMotherCategory(String name) {
		return getCategoryByNameAndMotherCategory(name, -1);
	}

	@Override
	public String getCategoryTreeStructure(Category category) {
		StringBuilder sb = new StringBuilder();
		if (category.getMotherCategory() != -1) {
			sb.append(getCategoryTreeStructure(getCategoriesById(category
					.getMotherCategory())));
			sb.append(" > ");
		}
		sb.append(category.getName());
		return sb.toString();
	}

	/*************************************
	 * Setter
	 *************************************/

	@Override
	public void saveCategory(Category category) {
		// modify the document
		BasicDBObject old = new BasicDBObject();
		old.put("id", category.getId());
		BasicDBObject update = new BasicDBObject();
		update.put("id", category.getId());
		update.put("name", category.getName());
		update.put("motherCategoryId", category.getMotherCategory());

		// save it into collection
		categoryCollection.update(old, update);
	}

	@Override
	public void saveCategories(List<Category> categories) {
		for (Category c : categories)
			saveCategory(c);
	}

	/*************************************
	 * Deletion
	 *************************************/

	@Override
	public void deleteCategory(int id) {

		BasicDBObject searchQuery = new BasicDBObject();
		searchQuery.put("id", id);

		categoryCollection.remove(categoryCollection.findOne(searchQuery));
	}

	@Override
	public void clearDB() {
		categoryCollection.drop();
		currentId=0;
	}
}
